package bancosys.tec.utils.db.converter;

import java.io.File;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Class written using OracleToHsqlDbConverter as reference.
 * 
 * @author piercio
 * @created Oct 28, 2008
 */
public class OracleToH2Converter extends StatementDbConverter {
    private final Set<String> numberFields = new TreeSet<String>();

    private static final Pattern NUMBER_FIELD_PATTERN = Pattern.compile("(\\w+)\\s+NUMBER\\s*\\(\\s*\\d+\\s*\\)\\s+NOT\\s+NULL");

    private static final String PK_PATTERN_DEF =
            "ALTER\\s+TABLE\\s+(\\w+)\\s+ADD\\s+CONSTRAINT\\s+\\w+\\s+PRIMARY\\s+KEY\\s*\\(\\s*(\\w+)\\s*\\)";

    private static final Pattern PK_PATTERN = Pattern.compile(PK_PATTERN_DEF);

    private static final Pattern UNIQUE_PATTERN =
            Pattern.compile("ALTER\\s+TABLE\\s+\\w+\\s+ADD\\s+CONSTRAINT\\s+\\w+\\s+UNIQUE\\s*\\(\\s*(\\w+(,\\s*)?)+\\s*\\)");

    private static final Pattern AUTH_FIELD_PATTERN = Pattern.compile("AUTH VARCHAR2\\(1 CHAR\\) DEFAULT '0'");

    private static final Pattern VARCHAR_FIELD_PATTERN = Pattern.compile("VARCHAR2\\(([0-9]+)( CHAR)?\\)");

    private static final Pattern INT_FIELD_PATTERN = Pattern.compile("NUMBER\\(\\d+(?:,0)?\\)");

    /**
     * Construtor.
     * 
     * @param inputFile arquivo de entrada.
     * @param outputFile arquivo de saida.
     * @param dbName nome do banco.
     * @throws FileNotFoundException caso nao encontre arquivo.
     * @throws MalformedURLException url malformada.
     */
    public OracleToH2Converter(File inputFile, File outputFile, String dbName) throws FileNotFoundException, MalformedURLException {
        super(inputFile, outputFile, dbName);
    }

    /**
     * Construtor.
     * 
     * @param inputFile arquivo de entrada.
     * @param outputFile arquivo de saida.
     * @param dbName nome do banco.
     */
    public OracleToH2Converter(URL inputFile, File outputFile, String dbName) {
        super(inputFile, outputFile, dbName);
    }

    /**
     * @param str statement.
     * @return statement convertido.
     */
    @Override
    protected String convertStatement(String str) {
        String s = str;

        // Ignore
        if (s.startsWith("COMMENT") || s.startsWith("CREATE UNIQUE") || s.startsWith("--") || s.startsWith("CREATE UNIQUE INDEX")) {
            return null;
        }

        Matcher uniqMatcher = UNIQUE_PATTERN.matcher(s);
        if (uniqMatcher.find()) {
            return null;
        }

        Matcher fieldMatcher = NUMBER_FIELD_PATTERN.matcher(s);
        while (fieldMatcher.find()) {
            this.numberFields.add(fieldMatcher.group(1));
        }

        Matcher pkMatcher = PK_PATTERN.matcher(s);
        if (pkMatcher.find() && this.numberFields.contains(pkMatcher.group(2))) {
            s = s.replaceAll(PK_PATTERN_DEF, "\nALTER TABLE $1 ALTER COLUMN $2 IDENTITY\n");
        }

        s = AUTH_FIELD_PATTERN.matcher(s).replaceAll("AUTH BOOLEAN DEFAULT FALSE");

        s = VARCHAR_FIELD_PATTERN.matcher(s).replaceAll("VARCHAR($1)");

        s = INT_FIELD_PATTERN.matcher(s).replaceAll("INT");

        return s;
    }

    /**
     * @param line a linha.
     * @return <code>true</code> se encontrar delimitador, <code>false</code> se nao.
     */
    @Override
    protected boolean gotDelimiter(String line) {
        return line.matches("^" + this.getOldStatementDelimiterChar() + "$");
    }

    /**
     * @return delimitador velho.
     */
    @Override
    protected char getOldStatementDelimiterChar() {
        return '/';
    }

    /**
     * @return delimitador novo.
     */
    @Override
    protected char getNewStatementDelimiterChar() {
        return ';';
    }
}
